#include <ip2regionUtil.h>
#include <adapter_controller.h>
#include <packet_controller.h>
#include <loguru/loguru.hpp>
#include <httplib.h>
#include <miscutil.hpp>
#include <tshark_manager.h>
#include <tshark_database.h>
#include <translateUtil.h>
#include <tshark_datatype.h>
#include <pugixml.hpp>
#include <json/json.h>
#include <iostream>
#include <sqlite3.h>
#include <stdio.h>
#include <fstream>

// #define FMT_HEADER_ONLY

#if 1 // httplib 测试
void startListen()
{
    // 1、创建一个server
    httplib::Server sev;
    // 2、创建一个get路由
    sev.Get("/hello", [](const httplib::Request &req, httplib::Response &res)
            {   
        std::string addr = fmt::format("{}:{}", req.remote_addr,req.remote_port);
        std::string name = req.get_param_value("name");
        res.set_content(fmt::format("hello {}, you are {}!",name,addr), "text/plain"); });

    // 3、创建一个post路由
    sev.Post("/hello", [](const httplib::Request &req, httplib::Response &res)
             {
        Json::Value reqBody;
        Json::CharReaderBuilder builder;
        std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
        std::string errMsg;
        if(!reader->parse(req.body.c_str(),req.body.c_str()+req.body.size(),&reqBody,&errMsg)){
            std::cerr << errMsg << std::endl;
        }
        
        // 提取json的数据
        std::string ip;
        uint16_t port;
        if(reqBody.isMember("ip") && reqBody["ip"].isString()){
            ip = reqBody["ip"].asString();
        }else{
            res.status = 400;
            res.set_content("Missing 'ip' field in JSON", "text/plain");
            return;
        }
        if(reqBody.isMember("port") && reqBody["port"].asUInt()){
            port = reqBody["port"].asUInt();
        }else{
            res.status = 400;
            res.set_content("Missing 'port' field in JSON", "text/plain");
            return;
        } 
        
        Json::Value resBody;
        resBody["src_ip"] = ip;
        resBody["src_port"] = port;
        resBody["dst_ip"] = req.local_addr;
        resBody["dst_port"] = req.local_port;
        resBody["proto"] = "TCP";
        Json::StreamWriterBuilder writer;
        const std::string resStr = Json::writeString(writer, resBody);
        res.set_content(resStr,"application/json"); });

    // 4、创建两个钩子函数
    auto beforeRequest = [](const httplib::Request &req, httplib::Response &resp)
    {
        LOG_F(INFO, "Request received for %s", req.path.c_str());
        return httplib::Server::HandlerResponse::Unhandled;
    };

    auto afterResponse = [](const httplib::Request &req, httplib::Response &resp)
    {
        LOG_F(INFO, "Received response with status %d", resp.status);
    };

    // 设置钩子函数
    sev.set_pre_routing_handler(beforeRequest);
    sev.set_post_routing_handler(afterResponse);

    // 5、开始监听
    sev.listen("192.168.5.100", 8080);
}

void homework()
{
    httplib::Server server;

    server.Get("/user_info",
               [](const httplib::Request &req, httplib::Response &resp)
               {
                   // 1、验证 Authorization
                   std::string token = req.get_header_value("Authorization");
                   std::cout << token << std::endl;
                   // 2、提取参数
                   std::string username;
                   int age = -1;
                   if (!req.has_param("username"))
                   {
                       resp.status = 401;
                       resp.set_content("Unauthorized", "text/plain");
                       return;
                   }
                   if (!req.has_param("age"))
                   {
                       resp.status = 401;
                       resp.set_content("Unauthorized", "text/plain");
                       return;
                   }
                   username = req.get_param_value("username");
                   age = std::atoi(req.get_param_value("age").c_str());
                   if (age <= 0)
                   {
                       resp.status = 401;
                       resp.set_content("Unauthorized", "text/plain");
                       return;
                   }
                   Json::Value respJson;
                   respJson["status"] = "success";
                   respJson["username"] = username;
                   respJson["age"] = age;
                   respJson["message"] = fmt::format("Hello, {}! You are {} years old.", username, age);
                   Json::StreamWriterBuilder writer;
                   const std::string respJsonStr = Json::writeString(writer, respJson);
                   resp.set_content(respJsonStr, "application/json");
               });

    server.Post("/user_info", [](const httplib::Request &req, httplib::Response &resp) {

    });

    server.listen("192.168.5.100", 8080);
}
#endif

std::shared_ptr<Tshark::TsharkManager> g_tsharkManager = std::make_shared<Tshark::TsharkManager>("./resource", "editcap");

#if 1 // controller 测试
void controllerTest()
{
    std::shared_ptr<httplib::Server> server = std::make_shared<httplib::Server>();
    g_tsharkManager->openDataBase("./resource/packets.db");

    // 离线分析包
    Controller::PacketController packetController(server, g_tsharkManager);
    packetController.registerRoute();

    // 网卡流量分析
    Controller::AdaptorController adaptorController(server, g_tsharkManager);
    adaptorController.registerRoute();

    server->listen("192.168.5.100", 12345);
}

#endif

int main(int argc, char *argv[])
{

    // homework();
    loguru::init(argc, argv);
    loguru::add_file("./resource/log.txt", loguru::Truncate, loguru::Verbosity_MAX);
    std::string packName = "./resource/capture.pcap";
    if (!Util::Ip2RegionUtil::init("./resource/ip2region.xdb"))
    {
        return 0;
    }
    // g_tsharkManager->setCurrFilePath("./resource/capture.pcap");
    controllerTest();

#if 0 // 分析pcap文件
    Tshark::error_code analyRes = tsharkManager.analysisFile(packName);
    if (analyRes != Tshark::error_code::success)
    {
        auto ec = make_error_code(analyRes);
        LOG_F(ERROR, "%s\n", ec.category().message(ec.value()).c_str());
        return 0;
    }
    tsharkManager.printAllPackets();
#endif

#if 0 // tsharkmanager并打印所有数据,测试打印第3个包的16进制数据
    tsharkManager.printAllPackets();
    auto packHex = tsharkManager.getPacketHexData(3);
    if (packHex)
    {
        std::string hexStr;
        for (auto c : packHex.result)
        {
            char hex[16];
            sprintf(hex, "%02X ", c);
            hexStr += hex;
        }
        LOG_F(INFO, "%s", hexStr.c_str());
    }
#endif

#if 0 // 开启指定网卡抓包并存入数据库
    // 获取所有网卡
    auto adaptersRes = tsharkManager.getNetworkAdapter();
    if (!adaptersRes)
    {
        std::error_code ec = make_error_code(adaptersRes.ec);
        LOG_F(ERROR, "%s\n", ec.category().message(ec.value()).c_str());
        return 0;
    }
    for (auto &adapter : adaptersRes.result)
    {
        LOG_F(INFO, adapter.toString().c_str());
    }

    tsharkManager.startCapture("ens33","./resource/packets.db");
    std::string stop = "";
    std::cout << "enter q to quit" << std::endl;
    while (stop != "q")
    {
        std::cin >> stop;
    }
    tsharkManager.stopCapture();
#endif

#if 0 // 监视网卡流量,并将网卡流量转换为json文件 importance&&hard 
    tsharkManager.startMonitorAdaptersFlowTrend();

    std::string stop = "";
    std::cout << "enter q to quit" << std::endl;
    while (stop != "q")
    {
        std::cin >> stop;
    }
    std::map<std::string, std::map<long, long>> flowTrendData;
    tsharkManager.getAdapterFlowTrendData(flowTrendData);
    tsharkManager.stopMonitorAdaptersFlowTrend();

    // 将flowTrendData转换为json文件
    auto flowTrendData2Json = [](std::map<std::string, std::map<long, long>> &flowTrendData,const std::string& jsonFilePath)
    {
        Json::Value root;
        Json::Value data;
        for (auto flowTrendPair : flowTrendData)
        {
            Json::Value adapter;
            for (auto it : flowTrendPair.second)
            {
                Json::Value value;
                value["time"] = it.first;
                value["bytes"] = it.second;
                adapter.append(value);
            }
            data[flowTrendPair.first] = adapter;
        }
        root["data"] = data;
        std::ofstream ofs(jsonFilePath);
        if (!ofs.is_open())
        {
            LOG_F(ERROR, "failed in open file: %s", jsonFilePath.c_str());
        }
        Json::StreamWriterBuilder builder;
        const std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
        writer->write(root, &ofs);
    };
    flowTrendData2Json(flowTrendData,"./resource/flowTrendData.json");

#endif

#if 0 // 打开协议树的xml文件并转换为json
    std::ifstream ifs("./resource/packets.xml");
    if (!ifs.is_open())
    {
        return 0;
    }
    std::stringstream ss;
    ss << ifs.rdbuf();
    ifs.close();
    std::string content = ss.str();
    Json::Value root;
    Util::MiscUtil::xml2Json(content, root);
    // 将json保存到文件中
    std::ofstream ofs("./resource/flowTrend.json");
    if (!ofs.is_open())
    {
        return 0;
    }
    Json::StreamWriterBuilder builder;
    const std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
    writer->write(root, &ofs);

#endif

#if 0
    std::string content;
    // 得到xml转换的序列化json字符串
    bool res = tsharkManager.getPacketDetailInfo(1, content);
    if (!res)
    {
        std::cout << "xml error" << std::endl;
        return 0;
    }
    std::cout << content << std::endl;
#endif

#if 0 // 测试sqlite数据库
    // Tshark::TsharkDataBase dataBase;
    // dataBase.openDataBase("./resource/packets.db");
    // std::vector<std::shared_ptr<Tshark::DataType::Packet>> packetVec;
    // packetVec.push_back(std::make_shared<Tshark::DataType::Packet>());
    // dataBase.storePackets(packetVec);
    // std::vector<std::shared_ptr<Tshark::DataType::Packet>> packets;
    // dataBase.queryPackets(packets);
    // for(auto packet:packets){
    //     std::cout << packet->to_string() << std::endl;
    // }
    tsharkManager.openDataBase("./resource/packets.db");
    std::vector<std::shared_ptr<Tshark::DataType::Packet>> packets;
    tsharkManager.queryPackets("192.168.5.100", 22, packets);
    std::for_each(packets.begin(), packets.end(), [](auto &packetPtr)
                  { std::cout << packetPtr->to_string() << std::endl; });

#endif

    // std::string ip = "202.89.233.101";
    // Util::ParseResult r = ip2regionUtil.getIpLocation(ip);
    // if (!r)
    // {
    //     std::error_code ec = make_error_code(r.ec);
    //     std::cout << ec.category().message(ec.value()) << std::endl;
    // }
    // std::cout << r.location << std::endl;

    /*
    std::ifstream file(packName, std::ios::binary);
    if (!file)
    {
        std::cerr << fmt::format("无法打开文件：{}！\n", packName);
        return 0;
    }
    \/* note: 使用memcpy优雅解析pcap或者其他协议的方式:
        1、定义包头部结构体，将读取的字节memcpy过去
        2、定义包内容结构体，将读取的字节memcpy过去
    \/*
    // 处理pcap文件头部
    Protocol::PcapHeader pcapHeader;
    file.read(reinterpret_cast<char *>(&pcapHeader), sizeof(Protocol::PcapHeader));
    // 处理pcap文件的每个数据报文
    while (file)
    {
        // 读取报文头部
        Protocol::PacketHeader packetHeader;
        file.read(reinterpret_cast<char *>(&packetHeader), sizeof(Protocol::PacketHeader));
        if (!file)
            break;
        // 读取报文内容
        std::vector<unsigned char> data(packetHeader.caplen);
        file.read(reinterpret_cast<char *>(data.data()), packetHeader.caplen);

        // 打印数据
        std::cout << fmt::format("数据包[时间：{}  长度：{}]：", packetHeader.ts_sec, packetHeader.caplen);
        for (unsigned char byte : data)
        {
            printf("%02X ", byte);
        }
        std::cout << "\n";
    }
    file.close();

    */

    // // 使用pipe进行进程通信的方式读取包
    // std::string cmd = "tshark -r " + packName + " -T fields -e frame.number -e frame.time -e frame.cap_len -e ip.src -e ipv6.src -e tcp.srcport -e udp.srcport -e ip.dst -e ipv6.dst -e tcp.dstport -e udp.dstport -e _ws.col.Protocol -e _ws.col.Info";
    // FILE *pipe = popen(cmd.c_str(), "r");
    // char buffer[4096];
    // std::vector<Tshark::DataType::Packet> packets;
    // uint32_t file_offset = sizeof(Tshark::DataType::PcapHeader);
    // while (fgets(buffer, 4096, pipe))
    // {
    //     Tshark::DataType::Packet packet;
    //     packet.file_offset = file_offset;
    //     Tshark::DataType::ParseResult res = packet.parseLine(buffer);
    //     if (!res)
    //     {
    //         std::cerr << res.err_msg << std::endl;
    //     }
    //     Util::ParseResult result = ip2regionUtil.getIpLocation(packet.src_ip);
    //     if(result){
    //         packet.src_location = result.location;
    //     }
    //     result = ip2regionUtil.getIpLocation(packet.src_ip);
    //     packet.dst_location = ip2regionUtil.getIpLocation(packet.dst_ip);
    //     if(result){
    //         packet.dst_location = result.location;
    //     }
    //     packets.emplace_back(packet);
    //     file_offset += sizeof(Tshark::DataType::PacketHeader) + packet.cap_len;
    // }
    // pclose(pipe);

    // int count = 0;
    // for (auto &p : packets)
    // {
    //     ++count;
    //     std::cout << p.to_string() << std::endl; // 打印json格式packet包
    //     std::vector<unsigned char> buffer(p.cap_len);
    //     Tshark::DataType::ParseResult result = Tshark::DataType::readPacketHex(packName, p.file_offset + sizeof(Tshark::DataType::PacketHeader), p.cap_len, buffer);
    //     // std::cout << "Packet Hex: ";
    //     // for (unsigned char c : buffer) // 打印需要使用unsigned char，使用 char 会带符号，然后补充 FFFFFFXX
    //     // {
    //     //     printf("%02X ", c);
    //     // }
    //     std::cout << std::endl;
    // }
    // std::cout << count << std::endl;

    // #ifdef _DEBUG
    //     std::cin.get();
    // #endif
    return 0;
}
